use std::io::{BufRead, BufReader, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::time::{Instant};
use urlencoding::decode;
use crate::json::parser::JSON;

pub fn start_server() {
    let listener = TcpListener::bind("127.0.0.1:9528").unwrap();
    for stream in listener.incoming() {
        let stream = stream.unwrap();
        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    let mut buf_reader = BufReader::new(&mut stream);

    //读取请求头和内容长度：Content-length
    let (lines, content_length): (Vec<String>, usize) = read_headers(&mut buf_reader);

    //根据Content-Length读取请求体内容
    let mut body_str = read_content(&mut buf_reader, content_length);

    //读取请求方法
    let (method, action) = read_action(lines);

    println!("[Request]method:{},action:{}", method, action);

    if action == "/pretty" {
        body_str = decode(&body_str[5..]).unwrap().to_string();
        json_handler(stream, &body_str);
    } else {
        index_handler(stream);
    }
}

fn read_headers(buf_reader: &mut BufReader<&mut TcpStream>) -> (Vec<String>, usize) {
    //读取请求头和内容长度：Content-length
    let mut content_length = 0;
    let mut lines: Vec<String> = vec![];
    loop {
        let mut buf: Vec<u8> = Vec::new();
        buf_reader.read_until(b'\n', &mut buf).expect("读取请求头出错！");
        let mut line = String::from_utf8(buf).unwrap();
        if line.ends_with('\n') {
            line.pop();
            if line.ends_with('\r') {
                line.pop();
            }
        }
        println!("{}", line);
        if line.is_empty() {
            println!("Line is empty,break");
            break;
        }
        if line.starts_with("Content-Length: ") {
            content_length = (&line[16..]).parse::<usize>().unwrap();
            println!("Got Content-Length:{}", content_length);
        }
        lines.push(line);
    }
    println!("Content-Length:{}", content_length);
    return (lines, content_length);
}

fn read_content(buf_reader: &mut BufReader<&mut TcpStream>, content_length: usize) -> String {
    let mut body_str = String::new();
    if content_length == 0 {
        return body_str;
    }
    let mut total_read = 0;
    let mut buf = vec![1u8; 100];
    while let Ok(bytes_read) = buf_reader.read(&mut buf) {
        for i in 0..bytes_read {
            body_str.push(buf[i] as char);
        }
        total_read = total_read + bytes_read;
        if total_read == content_length {
            break;
        }
    }
    println!("body_str:{}", body_str);
    return body_str;
}

fn read_action(lines: Vec<String>) -> (String, String) {
    let method_line = lines.first().expect("请求头格式不对！");
    let split = method_line.split(" ").collect::<Vec<&str>>();
    let method = split.get(0).expect("请求头格式不对,缺少请求方法！");
    let action = split.get(1).expect("请求头格式不对，缺少请求资源！");
    (String::from(*method), String::from(*action))
}

fn index_handler(mut stream: TcpStream) {
    let status_line = "HTTP/1.1 200 OK";
    let length = HTML.len();
    let content_type = "text/html; charset=utf-8";
    let response = format!(
        "{status_line}\r\nContent-Type: {content_type}\r\nContent-Length: {length}\r\n\r\n{HTML}"
    );
    let bytes = response.as_bytes();
    stream.write_all(bytes).unwrap();
}

fn json_handler(mut stream: TcpStream, json_str: &String) {
    println!("格式化之前json_str:{}", json_str);
    let start = Instant::now();


    let json =  JSON::pretty(json_str);

    let duration = start.elapsed().as_millis();
    println!("格式化后的json:{}", json);
    println!("解析json花费{}毫秒", duration);


    let status_line = "HTTP/1.1 200 OK";
    let length = json.len();
    let content_type = "text/html; charset=utf-8";
    let response = format!(
        "{status_line}\r\nContent-Type: {content_type}\r\nContent-Length: {length}\r\n\r\n{json}"
    );
    let bytes = response.as_bytes();
    stream.write_all(bytes).unwrap();
}

const HTML: &str = r"<html>
        <head>
            <style>
                .header {
                    justify-content: center;
                    display: flex;
                }
                .main {
                    display: inline-flex;
                }

                .leftText {
                    width: 400;
                    height: 400;
                    word-break: break-all;
                    flex-wrap: wrap;
                    align-content: normal;
                }

                .rightText {
                    width: 800;
                    height: 400;
                    word-break: break-all;
                    flex-wrap: wrap;
                }

                .leftDiv {
                    margin-left: 100;
                }

                .btnDiv {
                    margin-left: 100;
                    margin-top: 50;
                }

                .btn {
                    width: 100;
                    height: 40;
                }
            </style>

            <script>
                // Example POST method implementation:
                async function postData(url = '', data = '') {
                    // Default options are marked with *
                    const response = await fetch(url, {
                        method: 'POST', // *GET, POST, PUT, DELETE, etc.
                        mode: 'cors', // no-cors, *cors, same-origin
                        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
                        credentials: 'same-origin', // include, *same-origin, omit
                        headers: {
                            // 'Content-Type': 'application/json'
                            'Content-Type': 'application/x-www-form-urlencoded',
                        },
                        redirect: 'follow', // manual, *follow, error
                        referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                        body: data // body data type must match 'Content-Type' header
                    });
                    return response.text(); // parses JSON response into native JavaScript objects
                }

                function pretty() {
                    let json = document.getElementById('leftText').value;
                    let params = 'json=' + encodeURIComponent(json)
                    postData('/pretty', params)
                        .then(data => {
                            console.log(data); // JSON data parsed by data.json() call
                            document.getElementById('rightText').value = data
                        });
                }
            </script>
            <title>JSON格式化工具 By Rust</title>
        </head>

        <body>
            <div class='header'> <h1>JSON格式化工具 By Rust</h1></div>
            <div class='main'>
                <div class='leftDiv'>
                    <h2>源字符串：</h2>
                    <textarea name='json' class='leftText' id='leftText'></textarea>
                </div>

                <div class='leftDiv'>
                    <h2>格式化字符串：</h2>
                    <textarea class='rightText' id='rightText'></textarea>
                </div>
            </div>
            <br>
            <div class='btnDiv'>
                <button onclick='pretty()' class='btn' title='格式化'>格式化</button>
            </div>
        </body>
    </html>";